package com.zsy.oauth2.config;

import com.zsy.oauth2.config.exception.CustomWebResponseExceptionTranslator;
import com.zsy.oauth2.config.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Arrays;

/**
 * @program: my-springcloud
 * @description: 认证服务
 * @author: zhaoshouyun
 * @create: 2020-04-15 13:36
 **/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    BCryptPasswordEncoder passwordEncoder;

    @Autowired
    DataSource dataSource;

    //自定义异常信息
    @Autowired
    CustomWebResponseExceptionTranslator customWebResponseExceptionTranslator;

    /**
     * 注入authenticationManager
     * 来支持 password grant type
     */
    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    JwtAccessTokenConverter jwtAccessTokenConverter;

    /**
     *token存储前进行增强
     **/
    @Autowired
    CustomTokenEnhancer customTokenEnhancer;


    //存储token 方式
    @Bean
    public TokenStore tokenStore() {
        // 基于 JDBC 实现，令牌保存到数据
        return new JdbcTokenStore(dataSource);
    }

    @Bean
    public ClientDetailsService jdbcClientDetails() {
        // 基于 JDBC 实现，需要事先在数据库配置客户端信息
        return new JdbcClientDetailsService(dataSource);
    }

    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
                .passwordEncoder(new BCryptPasswordEncoder())
                .tokenKeyAccess("permitAll()")
                //allow check token
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients();
    }


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //      将增强的token设置到增强链中,jwt必须这样写，否则会被customTOkenEnhancer覆盖掉，通过增强链放入即可
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        enhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer, jwtAccessTokenConverter));


        // 设置令牌
        endpoints.tokenStore(tokenStore())
                 .authenticationManager(authenticationManager)//支持password
                 .userDetailsService(userDetailsService)//支持refresh_token 获取新token
                  //设置支持JWT
                //  .accessTokenConverter(jwtAccessTokenConverter) 不能再这里直接设置相关增强，必须在增强链里设置，否则会无效
                 .tokenEnhancer(enhancerChain);

        //指定自定义异常
        endpoints.exceptionTranslator(customWebResponseExceptionTranslator);
    }


    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 读取客户端配置
        clients.withClientDetails(jdbcClientDetails());
        // 内存配置客户端
       /* clients
                // 使用内存设置
                .inMemory()
                // client_id
                .withClient("client")
                // client_secret
                .secret(passwordEncoder.encode("secret"))
                // 授权类型
                .authorizedGrantTypes("authorization_code","password")
                // 授权范围
                .scopes("app")
                // 注册回调地址
                .redirectUris("https://yunfeng.org.cn");*/
    }

}
